#include "hal_iic.h"
#include "bsp_usart.h"
#include  "LsdMem.h"
#include "LsdEEPROM.h"
//拓邦移植
static void delay_us(uint16_t nus)
{
	unsigned short i,k;
  for(k=0;k<nus;k++)
  {
    for(i=0;i<5;i++)
    {
    }
  }
//	for(uint16_t i = 0; i < nus; i++)
//	{
//		i++;i--;i++;i--;
//		i++;i--;i++;i--;
//		i++;i--;i++;i--;
//	


//	}
}
static void IIC_SDA_IN(void)  
{
		gpio_init(EEPROM_SDA_GPIO_Port, 					GPIO_MODE_IPU, 	    GPIO_OSPEED_50MHZ,	EEPROM_SDA_Pin); //输入模式
}	
	
static void IIC_SDA_OUT(void)
{
	gpio_init(EEPROM_SDA_GPIO_Port, 					GPIO_MODE_OUT_PP, 	GPIO_OSPEED_50MHZ,	EEPROM_SDA_Pin); //输出模式
	
}
	
static void IIC_Start(void)
{
	IIC_SDA_OUT();
	SCL_H;
	SDA_H;
	delay_us(5);
	SDA_L;
	delay_us(5);
	SCL_L;//钳住I2C总线，准备发送或接收数据
}

static void IIC_Stop(void)
{
	static uint16_t timeOut = 0;
	timeOut = 50;
	do
	{
		IIC_SDA_OUT();//sda线输出
		SCL_L;
		SDA_L;
		delay_us(5);
		SCL_H;
		delay_us(5);
		SDA_H;
		delay_us(5);
		IIC_SDA_IN();
	}while((SDA_read == 0) && timeOut--);
	IIC_SDA_OUT();
}

static uint8_t IIC_Wait_Ack(uint16_t timeout)  //判断数据线有没有被拉低
{
	uint16_t ucErrTime=0;
	IIC_SDA_IN();//SDA设置为输入
	SDA_H;
	delay_us(2);
	SCL_H;
	delay_us(2);
	while(SDA_read)  //如果数据线一直是高，停止IIC
	{
		ucErrTime++;
		if(ucErrTime > timeout)
		{
			IIC_Stop();
			return 1;
		}
	}
	SCL_L;//检测到器件应答，时钟输出0
	delay_us(1);
	return 0;
}

static void IIC_Ack(void)
{
	SCL_L;
	IIC_SDA_OUT();
	SDA_L;
	delay_us(5);
	SCL_H;
	delay_us(5);
	SCL_L;
}

static void IIC_NAck(void)
{
	SCL_L;
	IIC_SDA_OUT();
	SDA_H;
	delay_us(5);
	SCL_H;
	delay_us(5);
	SCL_L;
}

static void IIC_Send_Byte(uint8_t txd)
{
	uint8_t t;
	IIC_SDA_OUT();
	delay_us(2);
	SCL_L;//拉低时钟开始数据传输
	delay_us(2);
	for(t=0; t<8; t++)
	{
		if((txd&0x80)>>7)
		{
			SDA_H;
		}
		else
		{
			SDA_L;
		}
		txd<<=1;
		delay_us(4);
		SCL_H;
		delay_us(4);
		SCL_L;
		delay_us(4);
	}
}

static uint8_t IIC_Read_Byte(unsigned char ack)
{
	unsigned char i, receive=0;
	IIC_SDA_IN();
	for(i=0; i<8; i++ )
	{
		SCL_L;
		delay_us(4);
		SCL_H;
		delay_us(1);
		receive<<=1;
		if(SDA_read)
			receive++;
		delay_us(1);
	}
	if (!ack)
	IIC_NAck();//发送nACK
	else
	IIC_Ack(); //发送ACK
	return receive;
}



static uint8_t AT24CXX_IsReady(void)
{
	IIC_Start();
	IIC_Send_Byte(0XA0);   //发送器件地址0XA0,写数据
	uint8_t ret = IIC_Wait_Ack(200);
	IIC_Stop();
	return ret;
}

void AT24CXX_WriteBuffs(uint16_t WriteAddr,uint8_t *buff, uint16_t len, uint16_t timeout)
{
  IIC_Start();
	if(EE_TYPE > AT24C16)
	{
		IIC_Send_Byte(0XA0);	    //发送写命令
		IIC_Wait_Ack(200);
		IIC_Send_Byte(WriteAddr>>8);//发送高地址
	}else IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据
	IIC_Wait_Ack(200);
  IIC_Send_Byte(WriteAddr%256);   //发送低地址
	IIC_Wait_Ack(200);
	for(uint16_t i = 0; i < len; i++)
	{

		if(buff)
		{
			IIC_Send_Byte(buff[i]);     //发送字节
		}
		else
		{
			IIC_Send_Byte(0);
		}
		IIC_Wait_Ack(200);
	}
  IIC_Stop();//产生一个停止条件
	//这里测试芯片是否准备好
	uint16_t timeOut = 20;
	while(AT24CXX_IsReady() && timeOut--){}
}

 HAL_StatusTypeDef OnEEPROMRead(uint16_t addr, uint8_t *retbuff, uint16_t retlen)
{
	IIC_Start();
	if(EE_TYPE > AT24C16)
	{
		IIC_Send_Byte(0XA0);	   //发送写命令
		IIC_Wait_Ack(200);
		IIC_Send_Byte(addr>>8);//发送高地址
	}else
		IIC_Send_Byte(0XA0+((addr/256)<<1));   //发送器件地址0XA0,写数据

	IIC_Wait_Ack(200);
  IIC_Send_Byte(addr%256);   //发送低地址
	IIC_Wait_Ack(200);
	IIC_Start();
	IIC_Send_Byte(0XA1+((addr/256)<<1));           //进入接收模式
	IIC_Wait_Ack(200);
	for(uint16_t i = 0; i < retlen; i++)
	{
		
		retbuff[i] = IIC_Read_Byte(1);
	}
  IIC_Stop();//产生一个停止条件
	return HAL_OK;
}

 HAL_StatusTypeDef OnEEPROMWrite(uint16_t addr, uint8_t *writebuff, uint16_t writelen)
{
//	 AT24CXX_WriteBuffs(addr,writebuff, writelen, 0xffff); 测试用
	
	static const uint8_t ERASEBUFF[]= {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
	//要先擦除当前地址 再写入
	if(writebuff)
	{
		//循环写数据  每次写8个数据  @7将夏工的8个数据改为4个数据为一页  增加写的稳定性
		uint16_t page = writelen / 4;
		if(writelen % 4)
		{
			page++;
		}
		EEPROM_WP_L;
		for(uint16_t i = 0; i < page; i++)
		{
			AT24CXX_WriteBuffs(addr + i * 4, (uint8_t *)ERASEBUFF, 4, 0xFFFF);// 20231222  把这里去掉时间从440ms 减少到220ms
			AT24CXX_WriteBuffs(addr + i * 4, &writebuff[i * 4], (writelen >= 4) ? 4: writelen, 0xFFFF);
		}
		EEPROM_WP_H;
	}
	return HAL_OK;
}


uint8_t OnEEPROMWriteTest(void)
{
	  uint8_t writebuff[3] ={0x11,0x22,0x33} ;
	  uint8_t retbuff[3];

    OnEEPROMWrite(0, writebuff, 3);    
		OnEEPROMRead(0, (uint8_t *)&retbuff[0], 3);
//		print_debug("OnEEPROMRead1:%d\r\n",retbuff[0]);
//		print_debug("OnEEPROMRead2:%d\r\n",retbuff[1]);
//		print_debug("OnEEPROMRead3:%d\r\n",retbuff[2]);
    
			return 0;
}

void OnMallocErrorCB(uint8_t type)
{
//	EEPROMDevInfo.mark.mallocError++;
//	OnEEPROMWrite(EEPROM_ADDR_DEV_MARK, (uint8_t *)&EEPROMDevInfo.mark, sizeof(EEPROMDevInfo.mark));
	print_debug("mem malloc error!\n");
	print_debug("MemUseCnt: %d\r\n",MemUseCnt);
		//测试重启前的状态
	uint32_t errorCnt = powerDownSave.max_life5 ;
	errorCnt++;
	powerDownSave.max_life5 = errorCnt;
	OnEEPROMSaveAllITLVInfo();
	//测试重启前的状态end
	while(1);
}
